///******************************************************************************
//  Lab 9 - Etch-a-Sketch
//
//  Description:
//
//	"Write a C language program that uses the sampled values from two
//	potentiometers to draw (etch) lines on the LCD. Use a low-pass filter
//	to smooth out the sampled values. Program one push button to clear
//	the LCD and another to toggle the size of the drawing pen. Display
//	the pen coordinates in the lower right corner of the display."
//
//   Author:	Paul Roper, Brigham Young University
//				March 2010
//				11/09/2010	simplfied routine
//
//   Built with Code Composer Studio Version: 4.0.1
//*******************************************************************************
//
//	                  MSP430F2274 (REV C)
//	               .----------------------.          LEFT         RIGHT
//	     RED LED-->|P1.0    (ACLK/A0) P2.0|<--SW_1
//	   GREEN LED-->|P1.1   (SMCLK/A1) P2.1|<--(H)    SW_2         EZ0_TX
//	eZ430 BUTTON-->|P1.2     (TA0/A2) P2.2|<--(D)    ADXL_INT     SW_3
//	           N.C.|P1.3     (TA1/A3) P2.3|<--(E)    SW_4         SERVO_3
//	           N.C.|P1.4     (TA2/A4) P2.4|-->(F)    LCD_BLT      SERVO_4
//	           N.C.|P1.5              P2.5| N.C.
//	           N.C.|P1.6          XIN P2.6|-->LED_1
//	           N.C.|P1.7         XOUT P2.7|-->LED_2
//                 |     (UCB0STE/A5) P3.0|-->i2c_RST
//                 |        (UCB0SDA) P3.1|<->i2c_SDA
//                 |        (UCB0SCL) P3.2|-->i2c_SCL
//                 |        (UCB0CLK) P3.3|-->LED_3/EZ0_RX
//	               |                  P3.4| N.C.
//	               |                  P3.5| N.C.
//	               |                  P3.6| N.C.
//	               |                  P3.7| N.C.
//	               |                  P4.0| N.C.
//	               |                  P4.1| N.C.
//	               |                  P4.2| N.C.
//	               |        (TB0/A12) P4.3|-->(G)    RPOT         EZ0_AN
//	               |        (TB1/A13) P4.4|-->(A)    LPOT         SERVO_1
//	               |        (TB2/A14) P4.5|-->(B)    TRANSDUCER   SERVO_2
//	               |     (TBOUTH/A15) P4.6|-->(C)    THERMISTOR   LED_4
//	               |                  P4.7| N.C.
//	               '----------------------'
//
//******************************************************************************
//
#include <math.h>
#include <stdio.h>
#include <stdlib.h>

#include "msp430x22x4.h"
#include "eZ430X.h"
#include "lcd.h"
#include "adc.h"
#include "graphics.h"
#include "etch-a-sketch.h"

//------------------------------------------------------------------------------
// INITIALIZE SYSTEM CONSTANTS/VARIABLES
//

volatile int WDT_cps_cnt;				// WD counts/second
volatile int lastX, lastY;
volatile int currentX, currentY;
volatile int lastRawX, lastRawY;
volatile int currentRawX, currentRawY;
volatile int waitAWhile=TIMEOUT;
volatile int brushSize=1;
volatile int pushed=FALSE;

extern const unsigned char byu_image[];			// BYU logo

//------------------------------------------------------------------------------
//
void main(void)
{
	// init eZ430X development board
//	eZ430X_init(CALDCO_8MHZ);			// init board
//	ADC_init();							// init ADC
//	lcd_init();							// init LCD
//	lcd_FRAM_init();					// clear lcd FRAM memory

	ERROR2(eZ430X_init(_8MHZ));			// init eZ430X board
	ERROR2(ADC_init());					// init a/d convertor
	ERROR2(lcd_init());					// init lcd
	ERROR2(lcd_FRAM_init());			// init FRAM


	// configure Watchdog
	WDT_cps_cnt = WDT_CPS;				// set WD 1 second counter
	WDTCTL = WDT_CTL;					// set WC interval to ~32ms
	IE1 |= WDTIE;						// enable WDT interrupt

	__bis_SR_register(GIE);				// enable interrupts

	// update display (interrupts enabled)
	lcd_image(byu_image, 40, 11);		// display BYU
	lcd_backlight(ON);					// turn on LCD backlight
	lcd_display(LCD_2X_FONT|LCD_PROPORTIONAL);
	lcd_cursor(4, 2);					// set display coordinates
	lcd_printf("Etch-a-Sketch");
	lcd_display(~(LCD_2X_FONT|LCD_PROPORTIONAL));
	wait(10);
	currentX=lastX=scaleX(currentRawX=lastRawX=ADC_read(RIGHT_POT));
	currentY=lastY=scaleY(currentRawY=lastRawY=ADC_read(LEFT_POT));
	while (1)
	{
		
		P2IFG &= 0x00;
		P2IE |= 0x0f;						// turn on interrupts
		waitForMovement();
		drawPoints();
		lcd_cursor(100, 0);					// output coordinates
		lcd_printf("%d,%d   ", currentX, currentY);
	}
} // end main

void waitForMovement(void){
	while ((currentX-lastX+currentY-lastY)==0){
		if (pushed){
			buttonPush();
			pushed=FALSE;
		}
		calcX();
		calcY();
	}	
}


void calcX(void){
	int x=0, i, t=0;
	for(i=x;i<SAMPLES;i++){
		if (++t%2){
			i--;
			continue;
		}
		x+=1023-ADC_read(RIGHT_POT);
	}
	x = x / SAMPLES;
	if (abs(x-lastRawX)> THRESHOLDX){
		currentRawX = x;
		currentX=scaleX(x);
	}
	return ;
}

void calcY(void){
	int y=0, i, t=0;
	for(i=y;i<SAMPLES;i++){
		if (++t%2){
			i--;
			continue;
		}
		y+=1023-ADC_read(LEFT_POT);
	}
	y = y/SAMPLES;
	if (abs(y-lastRawY)>THRESHOLDY){
		currentRawY = y;
		currentY=scaleY(y);
	}
	return ;
}


void drawPoints(void){
	int x, y, max, t;
	double dx, dy;
	lcd_backlight(ON);
	dx = currentX - lastX;
	dy = currentY - lastY;
	
	if (abs(dx)>abs(dy)){	// Determine how big the steps are for T
		max = abs(dx);
	}else {
		max = abs(dy);
	}
	
	if (brushSize==2){
		lcd_point(currentX,currentY,2);
	}

	for (t=0;t<max;t++){    // quick loop through so we can write points.
		
		x = lastX + t * dx / max; 	// Parametric equation for X
		y = lastY + t * dy / max; 	// Parametric equation for Y
		

		lcd_point(x, y, brushSize);	// draw on screen
		waitAWhile=TIMEOUT;
	}
	

	if (brushSize==2){
		lcd_circle(currentX,currentY,1);
	}

	lastX = currentX;
	lastY = currentY;
	
}

void saveToFRAM(void){
	int i,j;
	for (i=0;i<xPixels;i++){
		for (j=0;j<yPixels;j++){
			write_FRAM_point(i,j,lcd_point(i,j,4));
		}
	}
}

void readFromFRAM(void){
	int i,j;
	for (i=0;i<xPixels;i++){
		for (j=0;j<yPixels;j++){
				lcd_point(i,j,read_FRAM_point(i,j));
		}
	}
}

void clearScreen(void){
	
	
	ERROR2(lcd_init());
	ERROR2(lcd_FRAM_init());			// init FRAM
}

void buttonPush(void){
	int pushed = (0x0f&(0x0f^P2IN));
	int button2 = FALSE;
	switch (pushed){
		case 1:clearScreen();  break;
		case 2:button2=TRUE;   break;
		case 4:saveToFRAM();   break;
		case 8:readFromFRAM(); break;
	}
	if (button2==TRUE){
		if (brushSize==1){
			brushSize=3;
		}else if (brushSize==3){
			brushSize=2;
		}else if (brushSize==2){
			brushSize=1;
		}
	}
	
	while (0x0f&(0x0f^P2IN));
	
	P2IFG &= 0x00;
	P2IE |= 0x0f;						// turn on interrupts
}

/******************************************************************************
 *	Port 2 ISR														  		  *
 ******************************************************************************/
__interrupt void PORT2_ISR(void);
#pragma vector = PORT2_VECTOR
__interrupt void PORT2_ISR(void)
{
	P2IE &= ~0x0f;
	pushed=TRUE;
}


//------------------------------------------------------------------------------
//	Watchdog Timer ISR
//
__interrupt void WDT_ISR(void);
#pragma vector = WDT_VECTOR
__interrupt void WDT_ISR(void)
{
	if (--WDT_cps_cnt == 0)				// 1 second?
	{
		LED_GREEN_TOGGLE;				// toggle green LED
		WDT_cps_cnt = WDT_CPS;			// reset counter
		if(waitAWhile==0){
			lcd_backlight(OFF);
		}else if(waitAWhile>0){
			--waitAWhile;
		}
	}
	return;
} // end WDT_ISR
